/*
 * Copyright:  2018 smarabbit studio.
 *
 *  Licensed under the Confluent Community License; you may not use this file
 *  except in compliance with the License.  You may obtain a copy of the License at
 *
 *  http://www.confluent.io/confluent-community-license
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 *  WARRANTIES OF ANY KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations under the License.
 *
 *  @作   者： 黄开晖 (117227773@qq.com)
 *  @日   期:  2021年5月28日
 */
package com.massyframework.beanskin.runtime.modular;

import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import com.massyframework.beanskin.Developer;
import com.massyframework.beanskin.ModuleConfig;
import com.massyframework.beanskin.ModuleIdentifier;
import com.massyframework.beanskin.ModuleRepository;
import com.massyframework.beanskin.RequireLibraryDescriptor;
import com.massyframework.beanskin.util.version.Version;

/**
 * 抽象的模块配置项
 * @author huangkh
 *
 */
public abstract class AbstractModuleConfig implements ModuleConfig, ModuleIdentifier {
	
	protected final ModuleIdentifier identifier;
	private final String name;
	private final String description;
	private final Set<String> tags;
	private final List<RequireLibraryDescriptor> requires;
	private final Developer developer;
	
	private final ModuleRepository moduleRepository;

	/**
	 * 使用{@code builder}创建实例
	 * @param builder {@link Builder}
	 */
	protected AbstractModuleConfig(AbstractModuleBuilder builder) {
		this.identifier = Objects.requireNonNull(builder.identifier, "\"identifier\" cannot be null.");
		this.name = Objects.requireNonNull(builder.name, "\"name\" cannot be null.");
		this.description = builder.description;
		this.tags = builder.tags == null ?
				Collections.emptySet() :
					Collections.unmodifiableSet(builder.tags);
		this.moduleRepository = Objects.requireNonNull(builder.moduleRepository, "\"moduleRepository\" cannot be null.");
		this.requires = builder.requires == null ?
				Collections.emptyList() :
					Collections.unmodifiableList(builder.requires);
		this.developer = builder.developerShortName != null ?
				new DefaultDeveloper(builder.developerShortName, builder.developerName, builder.developerHomePage) :
					null;
	}
	
	@Override
	public String getGroupId() {
		return this.identifier.getGroupId();
	}
	
	@Override
	public String getModuleId() {
		return this.identifier.getModuleId();
	}
	
	@Override
	public Version getVersion() {
		return this.identifier.getVersion();
	}

	@Override
	public RequireLibraryDescriptor findByFilter(Predicate<RequireLibraryDescriptor> filter) {
		return this.requires.stream()
				.filter(filter)
				.findFirst()
				.orElse(null);
	}
	
	@Override
	public int size() {
		return this.requires.size();
	}

	@Override
	public boolean hasTag(String tag) {
		return this.tags.contains(tag);
	}

	@Override
	public Set<String> getTags() {
		return this.tags;
	}

	/**
	 * 模块唯一标识符
	 * @return {@link ModuleIdentifier}
	 */
	public ModuleIdentifier getModuleIdentifier() {
		return this.identifier;
	}

	@Override
	public List<RequireLibraryDescriptor> getRequires() {
		return this.requires;
	}

	@Override
	public List<RequireLibraryDescriptor> getRequires(Predicate<RequireLibraryDescriptor> filter) {
		return this.requires.stream()
					.filter(filter)
					.collect(Collectors.toList());
	}

	@Override
	public String getDescription() {
		return this.description;
	}

	@Override
	public String getName() {
		return this.name;
	}
	
	@Override
	public Developer getDeveloper() {
		return this.developer;
	}
	
	/**
	 * 模块资源库
	 * @return {@link ModuleRepository}
	 */
	protected ModuleRepository getModuleRepository() {
		return this.moduleRepository;
	}
	
	@Override
	public int compareTo(ModuleIdentifier o) {
		return this.identifier.compareTo(o);
	}

	
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((identifier == null) ? 0 : identifier.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		AbstractModuleConfig other = (AbstractModuleConfig) obj;
		if (identifier == null) {
			if (other.identifier != null)
				return false;
		} else if (!identifier.equals(other.identifier))
			return false;
		return true;
	}
}
